*! version 1.3 - Jun 28 2022 - added critical N; N_person variable; variable labels

capture program drop tess
program define tess

	syntax [anything]	[, init(string) ttest halt bonf(integer 1) mediation ks median]
	tokenize `"`anything'"'
	local term "`1'"
	local direction "`2'"

	* if option -init- is specified, call routine that creates new frame
	if "`init'" != "" {	
		Tess_init `init'
	}

	if "`ks'" != "" { // syntax -- option ks
				
		local type "ksmirnov"
		local direction ""
		
		tempname twop
		scalar `twop' = r(p)

		* get N -- note this overwrites r() and so no r() results can be retrieved afterward
		local term "`1'"
		local byterm "`2'"
		display "`term' : `byterm'"
		qui count if `term' < . & `byterm' < . // note: this overwrites r()
		local N = r(N)
	}
	
	else if "`ttest'" != "" {
		
		local type "ttest"
	
		local direction "`1'"
	
		local dif = r(mu_1) - r(mu_2)
		local se = r(se)
		tempname twop
		scalar `twop' = r(p)
		local N = r(N_1) // given that all t-tests are paired or tests against a scalar, this should work
		if r(sd_2) != . {
		* pooled SD
			* this is a simpler formula provided by cohen for doing computing
			* cohen's D and apparently there is not a clear benefit to one
			* that weights by difference in sizes between groups
			local sd_y = sqrt((r(sd_1)^2 + r(sd_2)^2) / 2) 
			local is_bin "yes" // t-test is necessarily a binary comparison, right?
		}
		else {
			* test against scalar
			local N = r(N_1)
			local sd_y = r(sd_1)
			local is_bin "no"
			
			if "`direction'" != "" {
				if ("`direction'"=="+" & r(t)>0) | ("`direction'"=="-" & r(t)<0) {
					local rightdir = "yes"
				}
				else if ("`direction'"=="-" & r(t)>0) | ("`direction'"=="+" & r(t)<0) {
					local rightdir = "yes"
				}
			}
			
		}
				
		local d = abs(`dif') / `sd_y'
	
	}

	else if "`mediation'" != "" {
		local type "mediation"
		tempname twop
		scalar `twop' = r(p)
		local N = e(N) // N of study
	}
	
	else {

		local type "default"
	
		local dif = _b[`term'] // mean difference
		local se = _se[`term'] // se for difference
		local N = e(N) // N of study

		* if clustered SE exists, save the quantity
		if e(N_clust) != . {
			local N_person = e(N_clust)
		}
		if e(N_g) != . {
			local N_person = e(N_g)
		}
		
		
		* p-value
		quietly test `term'
		tempname twop
		scalar `twop' = r(p)

		* mean of dependent variable 
			* obtained using estat summarize so that it should work if weights
			* are specified, etc.
		local depvar = "`e(depvar)'"
		tempname whatever
		quietly estat summarize
		mat `whatever' = r(stats)["`depvar'", 2]
		local sd_y = `whatever'[1,1]

		** is the term a binary variable

		local is_bin "no"
		sum `term' if e(sample) == 1
		if r(min) == 0 & r(max) == 1 {
			count if `term'	> 0 & `term' < 1 & e(sample) == 1
			if r(N) == 0 {
				local is_bin "yes"
			}
		}

		** does the term include an interaction operators
		
		local is_int "no"
		if strpos("`term'", "#") > 0 {
			local is_int "yes"
		}
		
		* Cohen's D
		local d = abs(`dif') / `sd_y'
				
	}	


	** make N_person equal to N if empty
	
	if "`N_person'" == "" {
		local N_person = `N'
	}

	** critical N

	if "`dif'" != "" & "`se'" != "" {

		* t/z statistic
		local tz = abs(`dif') / `se'
		
		* "critical se" = se associated with p of .5
		local crit_se = abs(`dif') / 1.96
		local crit_N = `N_person' * (`se' / `crit_se')^2
		local crit_N = round(`crit_N', 1)
	}
		
	
	** hypothesis number - uses maximum available number
	frame tess_results: capture quietly summarize num
	if r(max) == . {
		local num = 1
	}
	else {
		local num = r(max) + 1
	}
	
	** handle directional hypothesis
	
		** evaluate whether in correct direction and compute one-tailed p-value

	if "`direction'" != "" & "`dif'" != "." {
		
		* correct direction
		if (`dif' > 0 & "`direction'" == "+") | (`dif' < 0 & "`direction'" == "-") & `dif' < . {
			local onep = `twop' / 2
			local rightdir = "yes"
		}

		* wrong direction
		if (`dif' > 0 & "`direction'" == "-") | (`dif' < 0 & "`direction'" == "+") & `dif' < . {
			local onep = 1 - (`twop' / 2)
			local rightdir "no"
		}
		
	}

		
	local post_this "("${tess_study_name}") ("`type'") (`num') ("`direction'") (`dif') (`se') (`N') (`N_person') (`tz') (`crit_N') (`twop') (`onep') ("`rightdir'") (`sd_y') (`d') (`bonf') ("`is_bin'") ("`is_int'")"

	local post_this = subinstr(`"`post_this'"', "()", "(.)", .)
	
	* display `"`post_this'"'
	
	frame post tess_results `post_this'
	
	frame tess_results {
		label variable N "Number of observations"
		label variable N_person "Number of persons"
		label variable tz "t/z statistic (dif / se)"
		label variable dif "Difference"
		label variable se "Standard error"
		label variable twop "Two-tailed p-value"
		label variable onep "One-tailed p-value"
		label variable d "Cohen's d"
		label variable dir "Hypothesized direction"
		label variable sd_y "SD of outcome"
		label variable crit_N "Critical N (persons)"
		label variable rightdir "Is dif in hypothesized direction?"
		label variable num "Test hypothesis number"
		label variable bonf "Number of tests for Bonferroni correction"
		label variable is_bin "Is IV term binary?"
		label variable is_int "Does IV term include interaction operator?"
	}
	
	frame tess_results: describe
	
	frame tess_results: list
	
	frame tess_results: quietly save ${tess_study_name}-results, replace
	
	if "`halt'" != "" {
		error 999
	}
	
	
end

capture program drop Tess_init
program define Tess_init

	syntax namelist	
	tokenize `"`namelist'"'

	capture frame drop tess_results
	frame create tess_results str40 study str12 type num str4 dir dif ///
		se N N_person tz crit_N twop onep str8 rightdir sd_y d bonf ///
		str4 is_bin str4 is_int 
	
	global tess_study_name "`1'"
	
end


capture program drop Tess_coef
program define Tess_coef

	syntax namelist	
	tokenize `"`namelist'"'

end









